import uuid
import requests
import json
import time
import re
import asyncio
from config.settings import config
from db.repository.conversation_history import ConversationHistoryRepository
from services.prompt import prompt
from services.user import UserService
from services.prompt.prompt import PromptService
from services.llm import LLMService
from services.tools import tools_service
from services.pdf_import_service import create_pdf_import_service
# from services.reflection import ReflectionService  # 反思模块已注释
from services.context_manager import ContextManager
from sqlalchemy.orm import Session
from typing import Dict, Any, Optional, AsyncGenerator, List
from cache.redis import cache_service
from utils.logger import (
    emobot_logger,
    log_function_call,
    log_function_result,
    log_function_error,
)
from utils.performance_logger import (
    track_step,
    log_api_call,
    log_database_operation,
    log_cache_operation
)

logger = emobot_logger.get_logger()


def parse_action_and_sound_codes(response_text: str) -> Dict[str, Any]:
    """
    从LLM响应中解析动作代码序列和声音代码序列

    Args:
        response_text: LLM的完整响应文本

    Returns:
        Dict包含解析出的动作代码序列和声音代码序列
    """
    try:
        # 使用正则表达式提取动作代码序列和声音代码序列
        # 支持多种格式：动作代码序列: [1,2,3] 或 动作代码序列: 1,2,3 或 动作代码: 1
        action_pattern = r'动作代码序列?:\s*(\[.*?\]|\[STOP\]|\[NONE\]|[\d,\s]+|[\d]+)'
        sound_pattern = r'声音代码序列?:\s*(\[.*?\]|[\d,\s]+|[\d]+)'

        action_match = re.search(action_pattern, response_text)
        sound_match = re.search(sound_pattern, response_text)

        action_sequence = []
        sound_sequence = []

        if action_match:
            action_str = action_match.group(1).strip()
            # 处理不同的格式
            if action_str.startswith('[') and action_str.endswith(']'):
                # 格式: [1,2,3] 或 [STOP] 或 [NONE]
                if action_str in ['[STOP]', '[NONE]']:
                    action_sequence = [action_str]
                else:
                    try:
                        action_sequence = json.loads(action_str)
                    except:
                        # 如果JSON解析失败，尝试手动解析
                        action_str = action_str[1:-1]  # 去掉方括号
                        action_sequence = [int(x.strip()) for x in action_str.split(',') if x.strip().isdigit()]
            elif ',' in action_str:
                # 格式: 1,2,3
                action_sequence = [int(x.strip()) for x in action_str.split(',') if x.strip().isdigit()]
            else:
                # 格式: 1
                try:
                    action_sequence = [int(action_str)]
                except:
                    action_sequence = []

        if sound_match:
            sound_str = sound_match.group(1).strip()
            # 处理不同的格式
            if sound_str.startswith('[') and sound_str.endswith(']'):
                # 格式: [1,2,3]
                try:
                    sound_sequence = json.loads(sound_str)
                except:
                    # 如果JSON解析失败，尝试手动解析
                    sound_str = sound_str[1:-1]  # 去掉方括号
                    sound_sequence = [int(x.strip()) for x in sound_str.split(',') if x.strip().isdigit()]
            elif ',' in sound_str:
                # 格式: 1,2,3
                sound_sequence = [int(x.strip()) for x in sound_str.split(',') if x.strip().isdigit()]
            else:
                # 格式: 1
                try:
                    sound_sequence = [int(sound_str)]
                except:
                    sound_sequence = []

        # 如果解析成功，返回序列
        if action_sequence or sound_sequence:
            return {
                "动作代码序列": action_sequence,
                "声音代码序列": sound_sequence,
                "parsed": True
            }
        else:
            # 如果解析失败，返回原始响应
            return {
                "动作代码序列": [],
                "声音代码序列": [],
                "parsed": False,
                "raw_response": response_text
            }

    except Exception as e:
        logger.error(f"Error parsing action and sound code sequences: {e}")
        return {
            "动作代码序列": [],
            "声音代码序列": [],
            "parsed": False,
            "raw_response": response_text,
            "error": str(e)
        }


class ConversationService:
    def __init__(self, db: Session):
        self.db = db
        self.conv_history_repo = ConversationHistoryRepository(db)
        self.user_service = UserService(db)
        self.prompt_service = PromptService()
        self.llm_service = LLMService()
        self.pdf_import_service = create_pdf_import_service()
        # self.reflection_service = ReflectionService(self.llm_service)  # 反思模块已注释
        self.context_manager = ContextManager()
        logger.info("ConversationService initialized")

    def start_conversation(self, user_id: str) -> str:
        """Start a new conversation and return session ID"""
        start_time = time.time()
        log_function_call("start_conversation", {"user_id": user_id})

        try:
            logger.info(f"Starting new conversation for user {user_id}")
            session_id = str(uuid.uuid4())
            # You might want to initialize any conversation-specific data here

            duration = (time.time() - start_time) * 1000
            emobot_logger.log_conversation_event("start", user_id, session_id)
            log_function_result("start_conversation", session_id, duration)
            logger.info(f"New conversation started with session_id: {session_id}")

            return session_id
        except Exception as e:
            duration = (time.time() - start_time) * 1000
            log_function_error("start_conversation", e, {"user_id": user_id})
            logger.error(f"Failed to start conversation for user {user_id}: {e}")
            raise

    def get_user_info(self, user_id: str) -> Optional[Dict[str, Any]]:
        """Get user info from cache or database, return None if user doesn't exist"""
        start_time = time.time()
        log_function_call("get_user_info", {"user_id": user_id})

        try:
            # Try to get from cache first
            cache_key = f"user_info:{user_id}"
            cached_user_info = cache_service.get(cache_key)
            if cached_user_info:
                logger.info(f"User info found in cache for user {user_id}")
                emobot_logger.log_db_operation(
                    "cache_get", "user_info", {"user_id": user_id, "source": "cache"}
                )
                return cached_user_info

            # Try to get from database
            logger.info(f"User info not in cache, checking database for user {user_id}")
            user_profile = self.user_service.get_user_profile(user_id)
            if user_profile:
                # Cache the user info
                cache_service.set(cache_key, user_profile)
                logger.info(
                    f"User info retrieved from database and cached for user {user_id}"
                )
                emobot_logger.log_db_operation(
                    "cache_set", "user_info", {"user_id": user_id, "source": "database"}
                )
                return user_profile

            # User not found
            logger.warning(f"User profile not found for user {user_id}")
            emobot_logger.log_db_operation(
                "not_found", "user_profile", {"user_id": user_id}
            )
            return None

        except Exception as e:
            duration = (time.time() - start_time) * 1000
            log_function_error("get_user_info", e, {"user_id": user_id})
            # 兼容云侧老库：当字段缺失或查询异常时，降级为访客模式而不是抛出异常
            logger.warning(f"get_user_info failed for user {user_id}, fallback to guest mode: {e}")
            emobot_logger.log_db_operation(
                "fallback_guest", "user_profile", {"user_id": user_id, "error": str(e)}
            )
            return None

    async def process_message(
            self,
            user_id: str,
            session_id: str,
            user_message: str,
            # image_url: str = None,  # 云侧不再接收图像，参数已完全移除
    ) -> Dict[str, Any]:
        """Process user message and generate response (云侧不再接收图像数据)"""
        start_time = time.time()
        log_function_call(
            "process_message",
            {
                "user_id": user_id,
                "session_id": session_id,
                "message_length": len(user_message),
                # "has_image": image_url is not None,  # 云侧不再接收图像
            },
        )

        try:
            emobot_logger.log_conversation_event(
                "process_start",
                user_id,
                session_id,
                user_message,
                # {"has_image": image_url is not None},  # 云侧不再接收图像
                {},
            )

            # 步骤1: 获取用户信息（带缓存）
            with track_step("GET_USER_PROFILE", {"user_id": user_id}):
                user_profile = self.get_user_info(user_id)
                # 访客模式：如果没有用户档案，使用访客模式
                is_guest_mode = user_profile is None
                if is_guest_mode:
                    logger.info(f"User profile not found for user {user_id}, entering guest mode")
                    # 访客没有用户档案，user_profile保持为None

            # 步骤2: 获取对话历史
            with track_step("GET_CONVERSATION_HISTORY", {"session_id": session_id, "user_id": user_id}):
                conversation_history = self.get_conversation_history(session_id, user_id)

            # 步骤3: 保存用户消息到对话历史
            with track_step("SAVE_USER_MESSAGE",
                            {"user_id": user_id, "session_id": session_id, "message_length": len(user_message)}):
                self.save_message(user_id, session_id, user_message, None, "")  # image_url=None

            # 步骤4: 生成上下文提示词
            with track_step("GENERATE_CONTEXT_PROMPT", {"user_profile_exists": user_profile is not None,
                                                        "history_count": len(conversation_history),
                                                        "is_guest_mode": is_guest_mode}):
                context_prompt = self.prompt_service.generate_context_prompt(
                    user_profile, conversation_history, user_id, None, None, None, user_message, is_guest_mode
                )

            # 步骤4.5: 分析是否需要调用工具
            with track_step("ANALYZE_TOOL_NEED", {"user_message": user_message[:100]}):
                tool_analysis = await tools_service.analyze_tool_need(user_message)
                logger.info(f"Tool analysis result: {tool_analysis}")
            
            # 步骤4.6: 调用工具（如果需要）
            tool_results = {}
            if tool_analysis.get("needs_search", False):
                with track_step("WEB_SEARCH_TOOL", {"query": user_message}):
                    search_result = await tools_service.web_search(user_message)
                    tool_results["search"] = search_result
                    logger.info(f"Web search completed: {search_result.get('total_results', 0)} results")
            
            if tool_analysis.get("needs_weather", False):
                with track_step("WEATHER_TOOL", {"location": user_message}):
                    weather_result = await tools_service.get_weather(user_message)
                    tool_results["weather"] = weather_result
                    logger.info(f"Weather query completed: {weather_result.get('success', False)}")
            
            # 步骤4.7: 知识库检索（心理学相关内容）
            with track_step("KNOWLEDGE_BASE_SEARCH", {"query": user_message}):
                knowledge_results = self._search_knowledge_base(user_message)
                if knowledge_results:
                    tool_results["knowledge"] = knowledge_results
                    logger.info(f"Knowledge base search completed: {len(knowledge_results)} results")
            
            # 构建包含工具结果的提示词
            tool_context = ""
            if tool_results:
                tool_context = "\n\n工具调用结果:\n"
                if "search" in tool_results and tool_results["search"].get("success"):
                    search_data = tool_results["search"]
                    tool_context += f"搜索 '{search_data['query']}' 的结果:\n"
                    for i, result in enumerate(search_data.get("results", [])[:3], 1):
                        tool_context += f"{i}. {result.get('title', '无标题')}\n   {result.get('snippet', '无摘要')}\n   {result.get('url', '')}\n\n"
                
                if "weather" in tool_results and tool_results["weather"].get("success"):
                    weather_data = tool_results["weather"]["weather"]
                    tool_context += f"天气信息 ({weather_data.get('location', '未知地点')}):\n"
                    tool_context += f"温度: {weather_data.get('temperature', 0)}°C\n"
                    tool_context += f"体感温度: {weather_data.get('feels_like', 0)}°C\n"
                    tool_context += f"天气: {weather_data.get('description', '未知')}\n"
                    tool_context += f"湿度: {weather_data.get('humidity', 0)}%\n"
                    tool_context += f"风速: {weather_data.get('wind_speed', 0)} m/s\n\n"
                
                if "knowledge" in tool_results and tool_results["knowledge"]:
                    tool_context += f"心理学知识库检索结果:\n"
                    for i, result in enumerate(tool_results["knowledge"][:3], 1):
                        tool_context += f"{i}. 文件: {result.get('file_name', '未知')} (第{result.get('page_number', 0)}页)\n"
                        tool_context += f"   内容: {result.get('content', '')[:200]}...\n"
                        tool_context += f"   相似度: {result.get('similarity_score', 0):.2f}\n\n"

            prompt = f"{context_prompt}{tool_context}\n\nUser: {user_message}"

            # 步骤5: 调用LLM模型生成响应（场景识别功能已注释）
            with track_step("LLM_MODEL_CALL", {
                "prompt_length": len(prompt), 
                # "has_image": image_url is not None,  # 云侧不再接收图像
                "note": "场景识别功能已注释"
            }):
                # 场景识别功能已注释，云侧不再进行场景识别
                # bot_response = await self.llm_service.call_vlm_model(prompt, image_url)
                # 使用普通LLM调用替代
                messages = [{"role": "user", "content": prompt}]
                bot_response = self.llm_service.chat_completion(messages)

            # 步骤6: 上下文管理
            with track_step("CONTEXT_MANAGEMENT", {"user_message": user_message, "bot_response": bot_response}):
                context_result = self.context_manager.process_message(
                    user_id, session_id, user_message, bot_response, conversation_history
                )
                
                # 记录上下文处理结果
                logger.info(f"上下文处理: 主题={context_result['topic']}, 置信度={context_result['confidence']:.2f}, 操作={context_result['action']}")
                
                if context_result['cluster_id']:
                    logger.info(f"聚类ID: {context_result['cluster_id']}")

            # 步骤7: 同步反思检查（已注释以提升响应速度，节省约18秒）
            # with track_step("REFLECTION_CHECK", {"user_message": user_message, "bot_response": bot_response}):
            #     reflection_result = await self.reflection_service.reflect_on_response(
            #         user_message, bot_response
            #     )
            #     
            #     # 记录反思结果
            #     logger.info(f"反思结果: 满意度={reflection_result['satisfaction_score']}, 准确性={reflection_result['factuality_score']}")
            #     
            #     if reflection_result['needs_improvement']:
            #         logger.warning(f"回复需要改进: {reflection_result['issues']}")
            #         logger.info(f"改进建议: {reflection_result['suggested_improvement']}")

            # 步骤8: 更新机器人响应
            with track_step("UPDATE_BOT_RESPONSE", {"session_id": session_id, "response_length": len(bot_response)}):
                self.update_bot_response(session_id, user_message, bot_response)
                logger.info(f"Saved bot response to conversation history")

            # 步骤7: 触发情绪分析（每次对话后）
            # 性格分析只在对话结束时（process_conversation_end）进行
            if not is_guest_mode:  # 只对注册用户进行分析
                from services.tasks import analyze_emotion_after_message  # , analyze_personality_after_message
                # 获取当前对话轮数
                current_message_count = len(conversation_history) + 1
                
                # 触发情绪分析
                analyze_emotion_after_message.delay(user_id, session_id, user_message, current_message_count)
                logger.info(f"Triggered emotion analysis for user {user_id} after message {current_message_count}")
                
                # 性格分析已移至对话结束时（conversation end）进行
                # analyze_personality_after_message.delay(user_id, session_id, current_message_count)
                # logger.info(f"Triggered personality analysis for user {user_id} after message {current_message_count}")

            result = {
                "session_id": session_id,
                "response": bot_response,
                "user_id": user_id,
                "context_result": context_result,  # 包含上下文处理结果
                # "reflection_result": reflection_result  # 反思模块已注释
            }
            duration = (time.time() - start_time) * 1000

            emobot_logger.log_conversation_event(
                "process_complete",
                user_id,
                session_id,
                user_message,
                {
                    "response_length": len(bot_response),
                    "duration_ms": duration,
                },
            )
            log_function_result("process_message", result, duration)
            logger.info(f"Message processing completed in {duration:.2f}ms")

            return result
        except Exception as e:
            duration = (time.time() - start_time) * 1000
            log_function_error(
                "process_message",
                e,
                {
                    "user_id": user_id,
                    "session_id": session_id,
                    "message_length": len(user_message),
                    # "has_image": image_url is not None,  # 云侧不再接收图像
                },
            )
            logger.error(
                f"Error processing message for user {user_id}, session {session_id}: {e}"
            )
            raise

    async def _process_context_in_background(
            self,
            user_id: str,
            session_id: str,
            user_message: str,
            bot_response: str,
            conversation_history: List[Dict]
    ):
        """后台处理上下文管理（不阻塞主流程）"""
        try:
            context_result = self.context_manager.process_message(
                user_id, session_id, user_message, bot_response, conversation_history
            )
            
            # 记录上下文处理结果
            logger.info(f"[后台]上下文处理完成: 主题={context_result['topic']}, 置信度={context_result['confidence']:.2f}, 操作={context_result['action']}")
            
            if context_result['cluster_id']:
                logger.info(f"[后台]聚类ID: {context_result['cluster_id']}")
                
        except Exception as e:
            logger.error(f"[后台]上下文管理失败: {e}")
            # 后台任务失败不影响主流程

    async def process_message_streaming(
            self,
            user_id: str,
            session_id: str,
            user_message: str,
            # image_url: str = None,  # 云侧不再接收图像，参数已完全移除
    ) -> AsyncGenerator[Dict[str, Any], None]:
        """Process user message and generate streaming response (云侧不再接收图像数据)"""
        start_time = time.time()
        log_function_call(
            "process_message_streaming",
            {
                "user_id": user_id,
                "session_id": session_id,
                "message_length": len(user_message),
                # "has_image": image_url is not None,  # 云侧不再接收图像
            },
        )

        try:
            emobot_logger.log_conversation_event(
                "process_start",
                user_id,
                session_id,
                user_message,
                # {"has_image": image_url is not None},  # 云侧不再接收图像
                {},
            )

            # 1. Get user info with caching
            user_profile = self.get_user_info(user_id)
            # 访客模式：如果没有用户档案，使用访客模式
            is_guest_mode = user_profile is None
            if is_guest_mode:
                logger.info(f"User profile not found for user {user_id}, entering guest mode")
                # 创建访客用户档案
                user_profile = {
                    "user_id": user_id,
                    "name": "访客",
                    "avatar": None,
                    "age": None,
                    "gender": None,
                    "created_at": None,
                    "updated_at": None,
                    "is_guest": True
                }

            # 2. Get conversation history for this session
            conversation_history = self.get_conversation_history(session_id, user_id)

            # 3. Save user message to conversation history
            self.save_message(user_id, session_id, user_message, None, "")  # image_url=None

            # 4. Generate context prompt
            context_prompt = self.prompt_service.generate_context_prompt(
                user_profile, conversation_history, user_id, None, None, None, user_message, is_guest_mode
            )

            # 4.5: 分析是否需要调用工具
            tool_analysis = await tools_service.analyze_tool_need(user_message)
            logger.info(f"Tool analysis result: {tool_analysis}")
            
            # 4.6: 调用工具（如果需要）
            tool_results = {}
            if tool_analysis.get("needs_search", False):
                search_result = await tools_service.web_search(user_message)
                tool_results["search"] = search_result
                logger.info(f"Web search completed: {search_result.get('total_results', 0)} results")
            
            if tool_analysis.get("needs_weather", False):
                weather_result = await tools_service.get_weather(user_message)
                tool_results["weather"] = weather_result
                logger.info(f"Weather query completed: {weather_result.get('success', False)}")
            
            # 构建包含工具结果的提示词
            tool_context = ""
            if tool_results:
                tool_context = "\n\n工具调用结果:\n"
                if "search" in tool_results and tool_results["search"].get("success"):
                    search_data = tool_results["search"]
                    tool_context += f"搜索 '{search_data['query']}' 的结果:\n"
                    for i, result in enumerate(search_data.get("results", [])[:3], 1):
                        tool_context += f"{i}. {result.get('title', '无标题')}\n   {result.get('snippet', '无摘要')}\n   {result.get('url', '')}\n\n"
                
                if "weather" in tool_results and tool_results["weather"].get("success"):
                    weather_data = tool_results["weather"]["weather"]
                    tool_context += f"天气信息 ({weather_data.get('location', '未知地点')}):\n"
                    tool_context += f"温度: {weather_data.get('temperature', 0)}°C\n"
                    tool_context += f"体感温度: {weather_data.get('feels_like', 0)}°C\n"
                    tool_context += f"天气: {weather_data.get('description', '未知')}\n"
                    tool_context += f"湿度: {weather_data.get('humidity', 0)}%\n"
                    tool_context += f"风速: {weather_data.get('wind_speed', 0)} m/s\n\n"

            prompt = f"{context_prompt}{tool_context}"

            # 5. 生成完整的bot_response用于存储
            full_response = ""

            # 6. 流式调用LLM模型（场景识别功能已注释）
            # 场景识别功能已注释，云侧不再进行场景识别
            # async for chunk in self.llm_service.call_vlm_model_streaming(
            #         prompt, image_url
            # ):
            #     if not chunk.startswith("Error:"):
            #         full_response += chunk
            #         # 不直接发送chunk，而是等待完整响应后解析
            #     else:
            #         yield {
            #             "type": "error",
            #             "content": chunk,
            #             "session_id": session_id,
            #             "user_id": user_id,
            #         }
            
            # 使用普通LLM调用替代
            messages = [{"role": "user", "content": prompt}]
            full_response = self.llm_service.chat_completion(messages)

            # 7. 上下文管理（异步后台执行，不阻塞主流程，节省约5.5秒）
            # 启动后台任务处理上下文，不等待完成
            asyncio.create_task(
                self._process_context_in_background(
                    user_id, session_id, user_message, full_response, conversation_history
                )
            )
            logger.info(f"上下文管理已启动后台任务")

            # 8. 同步反思检查（已注释以提升响应速度，节省约18秒）
            # reflection_result = await self.reflection_service.reflect_on_response(
            #     user_message, full_response
            # )
            # 
            # # 记录反思结果
            # logger.info(f"流式反思结果: 满意度={reflection_result['satisfaction_score']}, 准确性={reflection_result['factuality_score']}")
            # 
            # if reflection_result['needs_improvement']:
            #     logger.warning(f"流式回复需要改进: {reflection_result['issues']}")
            #     logger.info(f"改进建议: {reflection_result['suggested_improvement']}")

            # 9. 解析动作代码序列和声音代码序列
            parsed_codes = parse_action_and_sound_codes(full_response)

            # 10. 发送解析后的代码序列（如果解析成功）
            if parsed_codes.get("parsed", False):
                # 发送代码序列响应
                action_sequence = parsed_codes.get("动作代码序列", [])
                sound_sequence = parsed_codes.get("声音代码序列", [])
                
                codes_response = f"动作代码序列: {action_sequence}\n声音代码序列: {sound_sequence}"
                yield {
                    "type": "codes",
                    "content": codes_response,
                    "动作代码序列": action_sequence,
                    "声音代码序列": sound_sequence,
                    "session_id": session_id,
                    "user_id": user_id,
                }
                logger.info(
                    f"Parsed code sequences - Action: {action_sequence}, Sound: {sound_sequence}")
            else:
                # 如果解析失败，发送原始响应
                yield {
                    "type": "raw",
                    "content": full_response,
                    "session_id": session_id,
                    "user_id": user_id,
                }
                logger.warning(f"Failed to parse codes from response: {full_response[:100]}...")

            # 11. 保存完整的回复到数据库
            if full_response and not full_response.startswith("Error:"):
                self.update_bot_response(session_id, user_message, full_response)
                logger.info(f"Saved bot response to conversation history")

            # 12. 触发情绪分析（每次对话后）
            # 性格分析只在对话结束时（process_conversation_end）进行
            if not is_guest_mode:  # 只对注册用户进行分析
                from services.tasks import analyze_emotion_after_message  # , analyze_personality_after_message
                # 获取当前对话轮数
                current_message_count = len(conversation_history) + 1
                
                # 触发情绪分析
                analyze_emotion_after_message.delay(user_id, session_id, user_message, current_message_count)
                logger.info(f"Triggered emotion analysis for user {user_id} after message {current_message_count}")
                
                # 性格分析已移至对话结束时（conversation end）进行
                # analyze_personality_after_message.delay(user_id, session_id, current_message_count)
                # logger.info(f"Triggered personality analysis for user {user_id} after message {current_message_count}")

            # 13. 发送完成信号
            duration = (time.time() - start_time) * 1000
            yield {
                "type": "complete",
                "content": full_response,
                "session_id": session_id,
                "user_id": user_id,
                "duration_ms": duration,
                "context_result": context_result,
                # "reflection_result": reflection_result,  # 反思模块已注释
            }

            emobot_logger.log_conversation_event(
                "process_complete",
                user_id,
                session_id,
                user_message,
                {
                    "response_length": len(full_response),
                    "duration_ms": duration,
                },
            )
            log_function_result("process_message_streaming", full_response, duration)
            logger.info(f"Message processing completed in {duration:.2f}ms")

        except Exception as e:
            duration = (time.time() - start_time) * 1000
            log_function_error(
                "process_message_streaming",
                e,
                {
                    "user_id": user_id,
                    "session_id": session_id,
                    "message_length": len(user_message),
                    # "has_image": image_url is not None,  # 云侧不再接收图像
                },
            )
            logger.error(
                f"Error processing message for user {user_id}, session {session_id}: {e}"
            )
            yield {
                "type": "error",
                "content": f"Error: {str(e)}",
                "session_id": session_id,
                "user_id": user_id,
            }

    def get_conversation_history(
            self, session_id: str, user_id: str
    ) -> list[Dict[str, Any]]:
        """Get conversation history for a session"""
        start_time = time.time()

        history = self.conv_history_repo.get_by_session_id(session_id)
        if not history:
            history = self.conv_history_repo.get_by_user_id(user_id)

        duration = (time.time() - start_time) * 1000

        # 记录数据库查询操作
        log_database_operation(
            operation="SELECT",
            table="conversation_history",
            duration_ms=duration,
            record_count=len(history) if history else 0
        )

        return [
            {
                "user_message": item.user_message,
                "bot_response": item.bot_response,
                # "image_url": item.image_url,  # 云侧不再返回图像URL
                "intent": item.intent,
                "created_at": item.created_at.isoformat(),
            }
            for item in history
        ]

    def save_message(
            self,
            user_id: str,
            session_id: str,
            user_message: str,
            image_url: str = None,
            intent: str = None,
    ) -> None:
        """Save user message to database"""
        start_time = time.time()

        self.conv_history_repo.create(
            {
                "user_id": user_id,
                "session_id": session_id,
                "user_message": user_message,
                "image_url": image_url,
                "intent": intent,
            }
        )

        duration = (time.time() - start_time) * 1000

        # 记录数据库插入操作
        log_database_operation(
            operation="INSERT",
            table="conversation_history",
            duration_ms=duration,
            record_count=1
        )

    def update_bot_response(
            self, session_id: str, user_message: str, bot_response: str
    ) -> None:
        """Update bot response in conversation history"""
        start_time = time.time()

        # Find the latest message with this session_id and user_message
        # In a real-world scenario, you might want to use a more precise identifier
        history = self.conv_history_repo.get_by_session_id(session_id)
        updated_count = 0
        for item in reversed(history):
            if item.user_message == user_message and not item.bot_response:
                self.conv_history_repo.update(item, {"bot_response": bot_response})
                updated_count = 1
                break

        duration = (time.time() - start_time) * 1000

        # 记录数据库更新操作
        log_database_operation(
            operation="UPDATE",
            table="conversation_history",
            duration_ms=duration,
            record_count=updated_count
        )

    def get_familiarity_context_for_prompt(
            self, user_id: str, scene_id: str = None, scene_name: str = None, vlm_scene_data: Dict[str, Any] = None
    ) -> str:
        """
        获取熟悉度上下文信息（根据端侧场景信息判断场景记忆）
        注意：此方法当前未被调用，保留以备将来使用

        Args:
            user_id: 用户ID
            scene_id: 场景ID（可选）
            scene_name: 场景名称（可选）
            vlm_scene_data: 端侧VLM分析结果中的场景数据（可选）

        Returns:
            str: 熟悉度描述文本
        """
        try:
            # 1. 计算用户熟悉度（基于对话轮数）
            user_familiarity = self._calculate_user_familiarity(user_id)

            # 2. 计算场景熟悉度
            if vlm_scene_data:
                # 如果有端侧VLM分析结果，使用VLM数据计算场景熟悉度
                scene_familiarity = self.calculate_scene_familiarity_from_vlm(vlm_scene_data)
            else:
                # 否则使用传统方式计算场景熟悉度
                scene_familiarity = self._calculate_scene_familiarity(scene_id, scene_name)

            # 3. 构建熟悉度描述
            familiarity_text = f"机器人与场景的熟悉程度：{scene_familiarity}\n机器人与人的熟悉程度：{user_familiarity}"

            logger.info(f"Familiarity context - User: {user_familiarity}, Scene: {scene_familiarity}")
            return familiarity_text

        except Exception as e:
            logger.error(f"Error getting familiarity context: {e}")
            return "机器人与场景的熟悉程度：未知\n机器人与人的熟悉程度：未知"

    def _calculate_user_familiarity(self, user_id: str) -> str:
        """
        基于用户档案存在与否计算用户熟悉度

        Args:
            user_id: 用户ID

        Returns:
            str: "熟悉" 或 "不熟悉"
        """
        try:
            # 检查用户档案是否存在
            user_profile = self.user_service.get_user_profile(user_id)
            
            # 有用户档案就是熟悉，没有就是不熟悉
            if user_profile:
                return "熟悉"
            else:
                return "不熟悉"

        except Exception as e:
            logger.error(f"Error calculating user familiarity: {e}")
            return "不熟悉"

    def _calculate_scene_familiarity(self, scene_id: str = None, scene_name: str = None) -> str:
        """
        基于场景记忆计算场景熟悉度（根据端侧场景信息判断场景记忆）

        Args:
            scene_id: 场景ID（可选）
            scene_name: 场景名称（可选）

        Returns:
            str: "熟悉" 或 "不熟悉"
        """
        try:
            # 如果没有场景信息，返回不熟悉
            if not scene_id and not scene_name:
                return "不熟悉"

            # 尝试从Weaviate获取场景访问信息
            try:
                from services.scene_memory import SceneMemoryService
                from config.weaviate_config import get_weaviate_client_config

                # 初始化场景记忆服务
                weaviate_config = get_weaviate_client_config()
                scene_memory_service = SceneMemoryService(
                    weaviate_url=weaviate_config["weaviate_url"],
                    openai_api_key=weaviate_config.get("openai_api_key"),
                    openai_base_url=weaviate_config.get("openai_base_url")
                )

                # 根据scene_id或scene_name查找场景
                if scene_id:
                    # 通过scene_id查找
                    collection = scene_memory_service.client.collections.get("Scene")
                    response = collection.query.fetch_objects(
                        where={"path": ["scene_id"], "operator": "Equal", "valueString": scene_id},
                        limit=1,
                        return_properties=["visit_count"]
                    )
                else:
                    # 通过scene_name查找
                    collection = scene_memory_service.client.collections.get("Scene")
                    response = collection.query.fetch_objects(
                        where={"path": ["scene_name"], "operator": "Equal", "valueString": scene_name},
                        limit=1,
                        return_properties=["visit_count"]
                    )

                if response.objects:
                    visit_count = response.objects[0].properties.get("visit_count", 0)
                    # 访问3次以上认为熟悉
                    if visit_count >= 3:
                        return "熟悉"
                    else:
                        return "不熟悉"
                else:
                    return "不熟悉"

            except Exception as e:
                logger.warning(f"Error accessing Weaviate for scene familiarity: {e}")
                return "不熟悉"

        except Exception as e:
            logger.error(f"Error calculating scene familiarity: {e}")
            return "不熟悉"

    def calculate_scene_familiarity_from_vlm(self, vlm_scene_data: Dict[str, Any]) -> str:
        """
        根据端侧VLM分析结果计算场景熟悉度

        Args:
            vlm_scene_data: 端侧VLM分析结果中的场景数据

        Returns:
            str: "熟悉" 或 "不熟悉"
        """
        try:
            if not vlm_scene_data:
                return "不熟悉"

            # 提取场景信息
            scene_category = vlm_scene_data.get("scene_category", "")
            supporting_details = vlm_scene_data.get("supporting_details", [])
            
            if not scene_category:
                return "不熟悉"

            # 构建场景查询条件
            scene_query = f"{scene_category}"
            if supporting_details:
                scene_query += f" {' '.join(supporting_details)}"

            # 使用场景记忆服务搜索相似场景
            try:
                from services.scene_memory import SceneMemoryService
                from config.weaviate_config import get_weaviate_client_config

                # 初始化场景记忆服务
                weaviate_config = get_weaviate_client_config()
                scene_memory_service = SceneMemoryService(
                    weaviate_url=weaviate_config["weaviate_url"],
                    openai_api_key=weaviate_config.get("openai_api_key"),
                    openai_base_url=weaviate_config.get("openai_base_url")
                )

                # 搜索相似场景
                similar_scenes = scene_memory_service.search_scene_memory(
                    query=scene_query,
                    search_type="all",
                    limit=5
                )

                if similar_scenes:
                    # 检查是否有高相似度的场景
                    for scene in similar_scenes:
                        if scene.get("similarity", 0) >= 0.7:  # 相似度阈值
                            logger.info(f"Found similar scene: {scene.get('scene', '')} with similarity: {scene.get('similarity', 0)}")
                            return "熟悉"
                    
                    # 如果有相似场景但相似度不够高，返回不熟悉
                    logger.info(f"Found similar scenes but similarity too low")
                    return "不熟悉"
                else:
                    logger.info(f"No similar scenes found for: {scene_category}")
                    return "不熟悉"

            except Exception as e:
                logger.warning(f"Error searching scene memory for familiarity: {e}")
                return "不熟悉"

        except Exception as e:
            logger.error(f"Error calculating scene familiarity from VLM: {e}")
            return "不熟悉"

    def process_vlm_analysis_result(self, vlm_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        处理VLM分析结果，提取场景信息并更新对话上下文

        Args:
            vlm_data: VLM分析结果数据

        Returns:
            Dict[str, Any]: 处理后的场景信息
        """
        try:
            # 验证VLM分析结果格式
            header = vlm_data.get("header", {})
            payload = vlm_data.get("payload", {})
            
            if not header.get("action") == "vlm-analysis-resp":
                logger.error("Invalid VLM analysis action type")
                return {"error": "Invalid action type"}
            
            if not header.get("status") == "success":
                logger.error(f"VLM analysis failed: {payload.get('message', 'Unknown error')}")
                return {"error": f"VLM analysis failed: {payload.get('message')}"}
            
            # 提取VLM分析结果
            results = payload.get("results", {})
            downstream = payload.get("downstream", {})
            
            # 处理环境分类结果
            env_classification = results.get("environment_classification", {})
            scene_category = env_classification.get("category", "unknown")
            scene_confidence = env_classification.get("confidence", 0.0)
            
            # 处理平面识别结果
            plane_recognition = results.get("plane_recognition", {})
            planes = plane_recognition.get("planes", [])
            
            # 处理手势/姿势识别结果
            gesture_pose = results.get("gesture_pose_recognition", {})
            gestures = gesture_pose.get("gestures", [])
            pose = gesture_pose.get("pose", "unknown")
            
            # 构建场景信息
            scene_info = {
                "task_id": header.get("task_id"),
                "scene_category": scene_category,
                "scene_confidence": scene_confidence,
                "planes": planes,
                "gestures": gestures,
                "pose": pose,
                "supporting_details": env_classification.get("supporting_details", []),
                "downstream": downstream,
                "timestamp": header.get("timestamp"),
                "vlm_analysis": {
                    "environment_classification": env_classification,
                    "plane_recognition": plane_recognition,
                    "gesture_pose_recognition": gesture_pose
                }
            }
            
            logger.info(f"VLM分析结果处理完成: {scene_category} (置信度: {scene_confidence})")
            return scene_info
            
        except Exception as e:
            logger.error(f"Error processing VLM analysis result: {e}")
            return {"error": str(e)}

    def update_scene_context_from_vlm(self, scene_info: Dict[str, Any]) -> str:
        """
        根据VLM分析结果更新场景上下文信息

        Args:
            scene_info: VLM分析结果

        Returns:
            str: 更新后的场景上下文描述
        """
        try:
            if "error" in scene_info:
                return "场景信息：未知（VLM分析失败）"
            
            scene_category = scene_info.get("scene_category", "unknown")
            scene_confidence = scene_info.get("scene_confidence", 0.0)
            supporting_details = scene_info.get("supporting_details", [])
            gestures = scene_info.get("gestures", [])
            pose = scene_info.get("pose", "unknown")
            
            # 构建场景上下文描述
            context_parts = []
            
            # 环境分类信息
            if scene_category != "unknown":
                context_parts.append(f"环境类型：{scene_category}")
                if scene_confidence > 0:
                    context_parts.append(f"识别置信度：{scene_confidence:.2f}")
            
            # 支持细节
            if supporting_details:
                context_parts.append(f"环境特征：{', '.join(supporting_details)}")
            
            # 手势和姿势信息
            if gestures:
                context_parts.append(f"检测到的手势：{', '.join(gestures)}")
            
            if pose != "unknown":
                context_parts.append(f"人物姿势：{pose}")
            
            # 平面识别信息
            planes = scene_info.get("planes", [])
            if planes:
                plane_descriptions = []
                for plane in planes:
                    plane_type = plane.get("type", "unknown")
                    semantic_label = plane.get("semantic_label", "未知")
                    confidence = plane.get("confidence", 0.0)
                    plane_descriptions.append(f"{semantic_label}({plane_type}, 置信度:{confidence:.2f})")
                context_parts.append(f"检测到的平面：{', '.join(plane_descriptions)}")
            
            if context_parts:
                scene_context = "场景信息：" + "；".join(context_parts)
            else:
                scene_context = "场景信息：未知"
            
            logger.info(f"场景上下文已更新: {scene_context}")
            return scene_context
            
        except Exception as e:
            logger.error(f"Error updating scene context from VLM: {e}")
            return "场景信息：未知（处理错误）"

    async def generate_sse_response(
            self,
            stream_generator: AsyncGenerator[Dict[str, Any], None],
            session_id: str,
            user_id: str,
    ) -> AsyncGenerator[str, None]:
        """Generate SSE (Server-Sent Events) response from streaming generator"""
        try:
            async for chunk in stream_generator:
                yield f"data: {json.dumps(chunk, ensure_ascii=False)}\n\n"
        except Exception as e:
            error_chunk = {
                "type": "error",
                "content": f"Streaming error: {str(e)}",
                "session_id": session_id,
                "user_id": user_id,
            }
            yield f"data: {json.dumps(error_chunk, ensure_ascii=False)}\n\n"
    
    def _search_knowledge_base(self, query: str) -> List[Dict[str, Any]]:
        """
        在知识库中搜索相关内容
        
        Args:
            query: 查询文本
            
        Returns:
            搜索结果列表
        """
        try:
            logger.info(f"搜索知识库: '{query[:50]}...'")
            
            results = self.pdf_import_service.search_knowledge(
                query=query,
                limit=3,
                similarity_threshold=0.7
            )
            
            logger.info(f"知识库搜索完成: 返回 {len(results)} 个结果")
            return results
            
        except Exception as e:
            logger.error(f"知识库搜索失败: {e}")
            return []
